﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Trackr.Dispatcher.Extensions
{
	/// <summary>
	/// Extension class for Type methods
	/// </summary>
	public static class TypeExtensions
	{
		/// <summary>
		/// Will check if one type implements an interface
		/// </summary>
		/// <param name="typeToCheck">the type to check</param>
		/// <param name="typeInterfaceDefinition">the interface, if the type is NOT an interface it will return false</param>
		/// <returns>Tru if the type implements interface</returns>
		public static bool ImplementsInterface(this Type typeToCheck, Type typeInterfaceDefinition)
		{
			if (!typeInterfaceDefinition.IsInterface)
				return false;
			return typeToCheck.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeInterfaceDefinition);
		}
		/// <summary>
		/// Will try to create an instance of the suplied type or return null if instansiation or cast failed
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="type"></param>
		/// <param name="parameters"></param>
		/// <returns></returns>
		public static T CreateInstance<T>(this Type type, params object[] parameters) where T : class
		{
			try
			{
				return Activator.CreateInstance(type, parameters) as T;
			}
			catch
			{
				return null;
			}
		}
		/// <summary>
		/// Will return all methods of a type with the specific attribute
		/// </summary>
		/// <typeparam name="T">The type of attribute</typeparam>
		/// <param name="type">The type to check</param>
		/// <param name="validationFilterDelegate">A custom function to validate the attributes</param>
		/// <returns>a list of methods</returns>
		public static IEnumerable<MethodInfo> GetMethodsWithAttribute<T>(this Type type, Func<IEnumerable<T>, bool> validationFilterDelegate = null) where T : Attribute
		{
			foreach (var method in type.GetMethods())
			{
				var attrList = method.GetCustomAttributes(typeof(T), true).Cast<T>();
				bool validates = true;
				if (validationFilterDelegate != null)
				{
					validates = validationFilterDelegate(attrList);
				}
				if (attrList.Any() && validates)
					yield return method;
			}
		}
		/// <summary>
		/// Will itterate through the assemblies and return the types that implement the type 
		/// </summary>
		/// <param name="assemblies">a list of assemblies</param>
		/// <param name="typeToHave">the type to filter</param>
		/// <returns>returns the types that implement the typeToHave type </returns>
		public static IEnumerable<Type> GetTypesThatInheritType(this IEnumerable<System.Reflection.Assembly> assemblies, Type typeToHave, bool filterOutInterfaces = true)
		{
			var publishTypes = assemblies.SelectMany(s => s.GetTypes())
						 .Where(p => p.IsInterface == !filterOutInterfaces) // i know this is weird with the negation but works for now...
						 .Where(type => typeToHave.IsAssignableFrom(type));
			return publishTypes;
		}
	}
}
